package com.windsea.relationshipmining.api;

/**
 * 
 */

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.channels.FileChannel;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import com.windsea.relationshipmining.database.DBUserData;

/** This class handles transfer operations to the central server. **/
public class TransferManager {
	private static final String TAG = "TransderManager";
	private HttpURLConnection connection = null;
	private DataOutputStream dos = null;
	private String boundary = "*****";
	private String twoHyphens = "--";
	private String lineEnd = "\r\n";
	private int bytesRead, bytesAvailable, bufferSize;
	private byte[] buffer;
	private int maxBufferSize = 1 * 1024 * 1024;
	private FileInputStream fileInputStream = null;
	private Context context = null;
	public static String SERVER_URL = "http://phonguyen.info/upload.php";
	private URL connectURL;

	// private static final Uri transfersUri =
	// DroidWatchProvider.Transfers.CONTENT_URI;
	// private static final Uri eventsUri =
	// DroidWatchProvider.Events.CONTENT_URI;

	/**
	 * Constructor used to set the context.
	 * 
	 * @param context
	 *            The application context.
	 */
	public TransferManager(Context context) {
		this.context = context;
	}

	/**
	 * This method performs the data transfer.
	 * 
	 * @return The transfer status.
	 */
	public boolean pushToServer(String filename) {
		// Find the file path of the SQLite database to transfer.
		String filePath = this.context.getDatabasePath(filename)
				.getAbsolutePath();
		Log.d(TAG, filePath);

		File data = Environment.getDataDirectory();
		String currentDBPath = "/data/" + "com.windsea.relationshipmining"
				+ "/databases/" + filename;
		File currentDB = new File(data, currentDBPath);

		try {
			fileInputStream = new FileInputStream(currentDB);
		} catch (FileNotFoundException e) {
			Log.e(TAG, e.getStackTrace().toString());
			return false;
		}

		// Create URL connect

		try {
			connectURL = new URL(SERVER_URL);
		} catch (Exception ex) {
			Log.i("URL FORMATION", "MALFORMATED URL");
		}

		// Open a HTTP connection to the URL
		try {
			connection = (HttpURLConnection) connectURL.openConnection();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.e(TAG, "HTTPURLCONNECTION: " + e.getMessage());
		}

		// Prepare to push the database file to the server using HTTPS POST
		try {
			connection.setDoInput(true);
			connection.setDoOutput(true);
			connection.setUseCaches(false);
		} catch (Exception e) {
			Log.e(TAG, "Error setting connection properties: " + e.getMessage());
			return false;
		}

		try {
			connection.setRequestMethod("POST");
		} catch (ProtocolException e) {
			Log.e(TAG, "Error: " + e.getMessage());
			return false;
		}

		// Prepare header information
		try {
			connection.setRequestProperty("Connection", "Keep-Alive");
			connection.setRequestProperty("Content-Type",
					"multipart/form-data;boundary=" + boundary);
		} catch (Exception e) {
			Log.e(TAG, "Error setting connection properties: " + e.getMessage());
			return false;
		}

		try {
			OutputStream os = connection.getOutputStream();
			if (os == null) {
				Log.e(TAG, "outputstream is null");
				return false;
			}
			dos = new DataOutputStream(os);
		} catch (Exception e) {
			Log.e(TAG, "Error creating output stream: " + e.getMessage());
			return false;
		}

		try {
			dos.writeBytes(twoHyphens + boundary + lineEnd);
			dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\""
					+ filename + "\"" + lineEnd);
			dos.writeBytes(lineEnd);
		} catch (Exception e) {
			Log.e(TAG, "Error writing initial output stream: " + e.getMessage());
			return false;
		}

		// Create a buffer of maximum size
		try {
			bytesAvailable = fileInputStream.available();
			bufferSize = Math.min(bytesAvailable, maxBufferSize);
			buffer = new byte[bufferSize];
		} catch (Exception e) {
			Log.e(TAG, "Error creating buffer: " + e.getMessage());
			return false;
		}

		// Write file into form and POST it to the server
		try {
			bytesRead = fileInputStream.read(buffer, 0, bufferSize);
		} catch (Exception e) {
			Log.e(TAG, "Error reading input file: " + e.getMessage());
			return false;
		}

		while (bytesRead > 0) {
			try {
				dos.write(buffer, 0, bufferSize);
				bytesAvailable = fileInputStream.available();
				bufferSize = Math.min(bytesAvailable, maxBufferSize);
				bytesRead = fileInputStream.read(buffer, 0, bufferSize);
			} catch (IOException e) {
				Log.e(TAG, "Error: " + e.getMessage());
				return false;
			}
		}

		// Verify a successful transfer
		int serverResponseCode = 0;
		try {
			dos.writeBytes(lineEnd);
			dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

			// Responses from the server (code and message)
			serverResponseCode = connection.getResponseCode();
			String serverResponseMessage = connection.getResponseMessage();

			// Close streams
			fileInputStream.close();
			dos.flush();
			dos.close();

			Log.i(TAG, "Code: " + serverResponseCode + " Message: "
					+ serverResponseMessage);
		} catch (IOException e) {
			Log.e(TAG, "Error: " + e.getMessage());
			return false;
		}

		if (serverResponseCode != 200)
			return false;
		return true;
	}

	/**
	 * This method performs a wipe of the local database after a successful
	 * transfer.
	 * 
	 * @return The transfer status.
	 */
	public boolean wipeDatabase() {
		// Delete all database
		DBUserData db = new DBUserData(this.context);
		db.open();
//		db.deleteContact();
		db.deleteCallLog();
		db.deleteSMS();
		return true;
	}

	public void exportDB() {
		File sd = Environment.getExternalStorageDirectory();
		File data = Environment.getDataDirectory();
		FileChannel source = null;
		FileChannel destination = null;
		String currentDBPath = "/data/" + "com.windsea.relationshipmining"
				+ "/databases/" + "userdataContacts";
		String backupDBPath = "userdataContacts";
		File currentDB = new File(data, currentDBPath);
		File backupDB = new File(sd, backupDBPath);
		try {
			source = new FileInputStream(currentDB).getChannel();
			destination = new FileOutputStream(backupDB).getChannel();
			destination.transferFrom(source, 0, source.size());
			source.close();
			destination.close();
			Log.d(TAG, "DB Exported!");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}